var pool = require('./conn'),
  mysql = require('mysql'),
  _ = require('lodash'),
  Log = require('../helper/logger'),
  tagLogger = new Log.TagLogger('CARPLUS-baseDao'),
  errorCode = require('../../conf/errorCode');

var query = (exports.query = pool.query);
exports.all = pool.query;
exports.queryBatch = pool.queryBatch;
exports.transactResolves = pool.transactResolves;
exports.getStr = pool.getStr;
exports.getConn = pool.getConn;

exports.prepareSql = function(sql, inserts) {
  return mysql.format(sql, inserts);
};

exports.getConst = function(columns, table, callback) {
  pool.get('SELECT ?? FROM ?? WHERE status = 0', [columns, table], callback);
};
exports.getConstAll = function(table, callback) {
  pool.get('SELECT * FROM ?? WHERE status = 0', [table], callback);
};

exports.delete = function(table, id, callback) {
  pool.get('UPDATE ?? set status = -1 where id = ?', [table, id], callback);
};

// table: <string: table name>
// id   : <integer: >
// param: <object: k-v>
exports.updateByIds = function(table, id, param, callback) {
  //query('UPDATE ?? SET ? WHERE id = ?', [table, param, id], callback);
  //pool.get('UPDATE ?? set status = 1 where id in (?)',[table,id],callback);
  let str = `UPDATE  ${mysql.escapeId(table)} set ? where id in (`;
  let count = 0;
  for (let i = 0; i < id.length; i++) {
    str += mysql.escape(id[i]);
    if (i < id.length - 1) {
      str += ',';
    }
  }
  str += ')';
  pool.get(str, [param], callback);
};

exports.deleteBatch = function(table, id, callback) {
  //pool.get('UPDATE ?? set status = 1 where id in (?)',[table,id],callback);
  let str = 'UPDATE ' + mysql.escapeId(table) + 'set status = -1 where id in (';
  let count = 0;
  for (let i = 0; i < id.length; i++) {
    str += mysql.escape(id[i]);
    if (i < id.length - 1) {
      str += ',';
    }
  }
  str += ')';
  pool.getStr(str, callback);
};

exports.addBatch = function(table, id, callback) {
  let str =
    'UPDATE ' +
    mysql.escapeId(table) +
    'set orders = orders + 1 where orders in (';
  let count = 0;
  for (let i = 0; i < id.length; i++) {
    str += mysql.escape(id[i]);
    if (i < id.length - 1) {
      str += ',';
    }
  }
  str += ')';
  pool.getStr(str, callback);
};

exports.insert = function(table, data, callback) {
  pool.get('INSERT into ?? SET ?', [table, data], callback);
};
exports.getPage = function(str, page, offset, callback) {
  pool.get(str, [(page - 1) * offset, offset + 0], callback);
};

exports.allNHoistFields = function(str, data, hoistFields, callback) {
  pool.get(str, data, (err, rows) => {
    if (err == null) {
      hoistFields = hoistFields || [];
      let rslt = _.pick(rows[0] || {}, hoistFields);
      rslt['prunedRows'] = _.map(rows, row => {
        return _.omit(row, hoistFields);
      });
      callback(null, rslt);
    } else {
      callback(err, null);
    }
  });
};
exports.getCount = function(table, callback) {
  pool.get(
    'SELECT count(1) as total FROM ?? where status = 0',
    [table],
    callback,
  );
};

var executeSingle = function(conn, data) {
  if (data.param) {
    return new Promise(function(resolve, reject) {
      conn.query(data.str, data.param, function(err, _rel) {
        if (err) {
          tagLogger.error(err);
          //reject(new Error('error:'+err));
          resolve(null);
        } else {
          resolve(_rel);
        }
      });
    });
  } else {
    return new Promise(function(resolve, reject) {
      conn.query(data.str, function(err, _rel) {
        if (err) {
          tagLogger.error(err);
          //reject(new Error('error:'+err));
          resolve(null);
        } else {
          resolve(_rel);
        }
      });
    });
  }
};

var gen = function*(conn, data, callback) {
  let result = [];
  for (let i = 0; i < data.length; i++) {
    let res = yield executeSingle(conn, data[i]);
    if (res == null) {
      return conn.rollback(function(err) {
        if (err) {
          tagLogger.error('数据库rollback失败！：' + data[i].str);
        }
        return callback({
          errNo: errorCode.DATABASE_ERROR,
          extraMsgs: `数据库操作失败: [${data[i].str}]`,
        });
      });
    }
    result[i] = res;
  }
  conn.commit(function(err) {
    if (err) {
      return conn.rollback(function() {
        tagLogger.error(err);
        return callback({
          errNo: errorCode.DATABASE_TRANSACTION_ERROR,
        });
      });
    }
    return callback(null, result);
  });
};

function run(conn, data, callback) {
  var g = gen(conn, data, callback);

  function next(data) {
    var result = g.next(data);
    if (result.done) return result.value;
    result.value
      .then(function(data) {
        next(data);
      })
      .catch(err => {
        tagLogger.error(err);
      });
  }

  next();
}

exports.executeMultipleQuery = function(data, callback) {
  pool.getConn(function(err, conn) {
    if (err) {
      return callback(err);
    }
    conn.beginTransaction(function(err) {
      if (err) {
        tagLogger.error(err);
        return callback({
          errNo: errorCode.DATABASE_TRANSACTION_ERROR,
        });
      }
      run(conn, data, callback);
    });
  });
};
